{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第三节 大语言模型LLMs，模版与聊天模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 大语言模型llm的常用参数与函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#输入三个模型各自的key\n",
    "\n",
    "import os\n",
    "from langchain_community.llms import Tongyi\n",
    "from langchain_community.llms import SparkLLM\n",
    "from langchain_community.llms import QianfanLLMEndpoint\n",
    "\n",
    "os.environ[\"DASHSCOPE_API_KEY\"] = \"\"\n",
    "\n",
    "os.environ[\"IFLYTEK_SPARK_APP_ID\"] = \"\"\n",
    "os.environ[\"IFLYTEK_SPARK_API_KEY\"] = \"\"\n",
    "os.environ[\"IFLYTEK_SPARK_API_SECRET\"] = \"\"\n",
    "\n",
    "os.environ[\"QIANFAN_AK\"] = \"\"\n",
    "os.environ[\"QIANFAN_SK\"] = \"\"\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### 参数 Temperature\n",
    "\n",
    "Temperature: 用于调整随机从生成模型中抽样的程度，因此每次“生成”时，相同的提示可能会产生不同的输出。温度为 0 将始终产生相同的输出。温度越高随机性越大！主要用于控制创造力。\n",
    "\n",
    "LLM中的一个耐人寻味的参数是 「温度」。「温度」是一个用于调整模型生成文本时创造性和多样性的超参数。「温度」是一个大于0的数值，通常在 0 到 1 之间。它影响模型生成文本时采样预测词汇的概率分布。当模型的「温度」较高时（如 0.8、1 或更高），模型会更倾向于从较多样且不同的词汇中选择，这使得生成的文本风险性更高、创意性更强，但也可能产生更多的错误和不连贯之处。而当「温度」较低时（如 0.2、0.3 等），模型主要会从具有较高概率的词汇中选择，从而产生更平稳、更连贯的文本。但此时，生成的文本可能会显得过于保守和重复。因此在实际应用中，需要根据具体需求来权衡选择合适的「温度」值。\n",
    "\n",
    "https://zhuanlan.zhihu.com/p/666670367"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 首先，让我们调用通义千问。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "llm_tongyi_di=Tongyi(temperature=0.1)\n",
    "llm_tongyi_zh=Tongyi(temperature=0.5)\n",
    "llm_tongyi_ga=Tongyi(temperature=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt0=\"请写一首有关大理的四言诗\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "大理风花雪，月映苍山洱。\n",
      "古城韵悠长，白族风情浓。\n",
      "崇圣寺三塔，影斜夕阳红。\n",
      "四季如春暖，人间仙境中。\n"
     ]
    }
   ],
   "source": [
    "print(llm_tongyi_di.invoke(prompt0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "大理风花雪，月映苍山洱。\n",
      "古城韵深厚，白族风情多。\n",
      "崇圣寺三塔，静诉千年史。\n",
      "四季如春日，人间仙境处。\n"
     ]
    }
   ],
   "source": [
    "print(llm_tongyi_zh.invoke(prompt0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "大理风光美，洱海映青天。\n",
      "苍山雪皑皑，古城韵悠然。\n",
      "风花雪月地，四季如春暖。\n",
      "白族三月街，繁华似锦繁。\n"
     ]
    }
   ],
   "source": [
    "print(llm_tongyi_ga.invoke(prompt0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 参数streaming——流式输出\n",
    "\n",
    "* 通义千问和星火似乎都不支持下面langchain中文文档中的流式输出模式，只有文心一言能用\n",
    "\n",
    "https://python.langchain.com.cn/docs/modules/model_io/models/chat/streaming"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler\n",
    "\n",
    "\n",
    "llm_wx_liu = QianfanLLMEndpoint(streaming=True, callbacks=[StreamingStdOutCallbackHandler()],temperature=0.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [03-04 20:22:55] openapi_requestor.py:316 [t:3588]: requesting llm api endpoint: /chat/eb-instant\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "当然可以，以下是一首关于西湖的歌：\n",
      "\n",
      "西湖之歌\n",
      "\n",
      "(诗词)\n",
      "\n",
      "水光潋滟晴方好，山色空蒙雨亦奇。\n",
      "欲把西湖比西子，淡妆浓抹总相宜。\n",
      "\n",
      "(副歌)\n",
      "\n",
      "西湖之歌，婉约又豪放，\n",
      "碧波荡漾，情深意长。\n",
      "柳丝轻舞，花儿笑开，\n",
      "西湖之美，让人心醉。\n",
      "\n",
      "(歌词)\n",
      "\n",
      "第一节：\n",
      "晨曦微露，西湖醒来，\n",
      "薄雾轻绕，如梦如幻。\n",
      "白鹭低飞，鱼儿跃起，\n",
      "碧波荡漾，心旷神怡。\n",
      "\n",
      "副歌：\n",
      "西湖之歌，婉约又豪放，\n",
      "碧波荡漾，情深意长。\n",
      "月下西湖，静谧又神秘，\n",
      "夜色西湖，如诗如画。\n",
      "\n",
      "第二节：\n",
      "雷峰塔倒，白娘子的传说，\n",
      "断桥残雪，千古传颂。\n",
      "苏堤春晓，花开如画，\n",
      "三潭印月，美不胜收。\n",
      "\n",
      "副歌：\n",
      "西湖之歌，婉约又豪放，\n",
      "碧波荡漾，情深意长。\n",
      "风吹湖面，涟漪荡漾，\n",
      "心随西湖，飘向远方。\n",
      "\n",
      "第三节和尾声：\n",
      "西湖之美，四季如画，\n",
      "春花秋月，夏阳冬雪。\n",
      "走过岁月，西湖依旧，\n",
      "我心中的西湖之歌，永远唱响。\n",
      "\n",
      "这首歌描绘了西湖的美丽景色和传说，表达了对西湖的深深喜爱和向往。希望你喜欢！"
     ]
    }
   ],
   "source": [
    "resp = llm_wx_liu.invoke(\"帮我写一首有关西湖的歌\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数get_num_tokens————计算token数量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "llm_tongyi_ga.get_num_tokens(\"fasfdsafreqwrwe\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数generate————多个提示词的支持\n",
    "\n",
    "* 注意对应信息获取方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "res0=llm_tongyi_di.generate([\"写一首四句的诗\",\"写一幅对联\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "LLMResult(generations=[[Generation(text='春风吹绿江南岸，桃花染红水中央。\\n燕舞蝶飞花间笑，一曲鸣莺万物芳。', generation_info={'finish_reason': 'stop', 'request_id': 'b8d8b34c-cf10-9624-987f-648083d13860', 'token_usage': {'input_tokens': 25, 'output_tokens': 27, 'total_tokens': 52}})], [Generation(text='上联：岁月长河泛金舟，历尽风霜喜庆收。\\n下联：人生旅途似玉带，铺满希望映朝晖。\\n横批：岁月如歌，人生如梦', generation_info={'finish_reason': 'stop', 'request_id': '308d4990-6877-9322-a6e3-ae6bf0c8ce16', 'token_usage': {'input_tokens': 23, 'output_tokens': 44, 'total_tokens': 67}})]], llm_output={'model_name': 'qwen-plus'}, run=[RunInfo(run_id=UUID('6659c526-92fb-4dc1-aefe-3145ffc93dec')), RunInfo(run_id=UUID('feb4517f-271d-4af8-8eb3-35e800987574'))])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'finish_reason': 'stop',\n",
       " 'request_id': 'b8d8b34c-cf10-9624-987f-648083d13860',\n",
       " 'token_usage': {'input_tokens': 25, 'output_tokens': 27, 'total_tokens': 52}}"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res0.generations[0][0].generation_info"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### classwork-1\n",
    "\n",
    "1. 让大模型帮忙写一幅对联，用get_num_tokens获得此提示词的token数量\n",
    "\n",
    "2. 改变模型的温度，看看对联是否有不一样？\n",
    "\n",
    "3. 通过流式输出上述对联的结果\n",
    "\n",
    "4. 通过列表定义任意几个提示词，通过generate获得多个提示词的生成结果, 并获得这些结果的total_tokens"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模版的使用\n",
    "\n",
    "### 简单模版\n",
    "\n",
    "语言模型以文本作为输入，这段文本通常被称为提示（Prompt）。通常情况下，这不仅仅是一个硬编码的字符串，而是模板、示例和用户输入的组合。LangChain提供了多个类和函数，以便轻松构建和处理提示。\n",
    "\n",
    "提示模板是指一种可复制的生成提示的方式。它包含一个文本字符串（模板），可以从最终用户处接收一组参数并生成提示。提示模板可能包含以下内容：\n",
    "\n",
    "* 对语言模型的指令\n",
    "* 少量示例，以帮助语言模型生成更好的回复\n",
    "* 对语言模型的问题\n",
    "\n",
    "原文链接： https://machinelearning.blog.csdn.net/article/details/131988052"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n我希望你能充当新公司的命名顾问。\\n一个生产彩色袜子的公司的好名字是什么？\\n'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain import PromptTemplate\n",
    "\n",
    "template = \"\"\"\n",
    "我希望你能充当新公司的命名顾问。\n",
    "一个生产{product}的公司的好名字是什么？\n",
    "\"\"\"\n",
    "\n",
    "prompt = PromptTemplate(\n",
    "    input_variables=[\"product\"],\n",
    "    template=template,\n",
    ")\n",
    "prompt.format(product=\"彩色袜子\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['product'], template='\\n我希望你能充当新公司的命名顾问。\\n一个生产{product}的公司的好名字是什么？\\n')"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'给我讲一个有趣的的关于小鸡的笑话。'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 多个输入变量的示例提示\n",
    "multiple_input_prompt = PromptTemplate(\n",
    "    input_variables=[\"adjective\", \"content\"], \n",
    "    template=\"给我讲一个{adjective}的关于{content}的笑话。\"\n",
    ")\n",
    "multiple_input_prompt.format(adjective=\"有趣的\", content=\"小鸡\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  包含例子的模版\n",
    "\n",
    "向模板添加Few Shot示例\n",
    "Few Shot示例是一组可以帮助语言模型生成更好响应的示例。要使用Few Shot示例生成提示，可以使用FewShotPromptTemplate。此类接受PromptTemplate和Few Shot示例列表。然后，它使用Few Shot示例格式化提示模板。\n",
    "\n",
    "在下面示例中，我们将创建一个生成单词反义词的提示："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Give the antonym of every input\n",
      "\n",
      "Word: happy\n",
      "Antonym: sad\n",
      "\n",
      "Word: tall\n",
      "Antonym: short\n",
      "\n",
      "Word: big\n",
      "Antonym: \n"
     ]
    }
   ],
   "source": [
    "from langchain import PromptTemplate, FewShotPromptTemplate\n",
    "\n",
    "# 首先，创建Few Shot示例列表\n",
    "examples = [\n",
    "    {\"word\": \"happy\", \"antonym\": \"sad\"},\n",
    "    {\"word\": \"tall\", \"antonym\": \"short\"},\n",
    "]\n",
    "\n",
    "# 接下来，我们指定用于格式化示例的模板。\n",
    "# 我们使用`PromptTemplate`类来实现这个目的。\n",
    "example_formatter_template = \"\"\"Word: {word}\n",
    "Antonym: {antonym}\n",
    "\"\"\"\n",
    "\n",
    "example_prompt = PromptTemplate(\n",
    "    input_variables=[\"word\", \"antonym\"],\n",
    "    template=example_formatter_template,\n",
    ")\n",
    "\n",
    "# 最后，创建`FewShotPromptTemplate`对象。\n",
    "few_shot_prompt = FewShotPromptTemplate(\n",
    "    # 这些是我们要插入到提示中的示例。\n",
    "    examples=examples,\n",
    "    # 这是我们在将示例插入到提示中时要使用的格式。\n",
    "    example_prompt=example_prompt,\n",
    "    # 前缀是出现在提示中示例之前的一些文本。\n",
    "    # 通常，这包括一些说明。\n",
    "    prefix=\"Give the antonym of every input\\n\",\n",
    "    # 后缀是出现在提示中示例之后的一些文本。\n",
    "    # 通常，这是用户输入的地方。\n",
    "    suffix=\"Word: {input}\\nAntonym: \",\n",
    "    # 输入变量是整个提示期望的变量。\n",
    "    input_variables=[\"input\"],\n",
    "    # 示例分隔符是我们将前缀、示例和后缀连接在一起的字符串。\n",
    "    example_separator=\"\\n\",\n",
    ")\n",
    "\n",
    "# 现在，我们可以使用`format`方法生成一个提示。\n",
    "print(few_shot_prompt.format(input=\"big\"))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'ugly'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "llm_tongyi_di(few_shot_prompt.format(input=\"美丽\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### classwork-2\n",
    "\n",
    "1. 通过引入带变量的模板，控制对联的类型，以此输出满足不同需求的对联\n",
    "\n",
    "2. 使用带例子的模板实现一个自动对对联工具，要求你给出上联，大模型给出对应下联，例子自己百度\n",
    "   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 聊天模型-chat_models\n",
    "\n",
    "聊天模型是语言模型的一种变体。虽然聊天模型在内部使用语言模型，但它们公开的接口略有不同。它们不是提供一个“输入文本，输出文本”的API，而是提供一个以“聊天消息”作为输入和输出的接口。 聊天模型的API还比较新，因此我们仍在确定正确的抽象层次。本问将介绍如何开始使用聊天模型，该接口是基于消息而不是原始文本构建的\n",
    "\n",
    "通过向聊天模型传递一个或多个消息，可以获取聊天完成的结果。响应将是一个消息。LangChain目前支持的消息类型有AIMessage、HumanMessage、SystemMessage和ChatMessage，其中ChatMessage接受一个任意的角色参数。大多数情况下，我们只需要处理HumanMessage、AIMessage和SystemMessage。\n",
    "                        \n",
    "原文链接：https://blog.csdn.net/hy592070616/article/details/131924904"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 通义千问，星火，文心一言的聊天模型实现\n",
    "\n",
    "#### 通义千问\n",
    "\n",
    "当前langchain版本（0.1.9）通义千问的流式接口有问题，暂时建议不用流式\n",
    "\n",
    "https://python.langchain.com/docs/integrations/chat/tongyi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import PromptTemplate, LLMChain\n",
    "from langchain.prompts.chat import (\n",
    "    ChatPromptTemplate,\n",
    "    SystemMessagePromptTemplate,\n",
    "    AIMessagePromptTemplate,\n",
    "    HumanMessagePromptTemplate,\n",
    ")\n",
    "from langchain.schema import (\n",
    "    AIMessage,\n",
    "    HumanMessage,\n",
    "    SystemMessage\n",
    ")\n",
    "\n",
    "from langchain_community.chat_models import ChatSparkLLM\n",
    "from langchain_community.chat_models.tongyi import ChatTongyi\n",
    "from langchain_community.chat_models import QianfanChatEndpoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.messages import HumanMessage\n",
    "\n",
    "chat_ty = ChatTongyi(\n",
    "    streaming=True,\n",
    ")\n",
    "res = chat_ty.stream([HumanMessage(content=\"hi\")], streaming=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "res = chat_ty.stream([HumanMessage(content=\"帮我写副对联\")], streaming=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "content='当然'\n",
      "content='可以'\n",
      "\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    for chunk in res:\n",
    "        print(chunk)\n",
    "except TypeError as e:\n",
    "    print(\"\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='当然可以，这里有一副适合春节的对联供您参考：\\n\\n上联：红梅傲雪春风暖，岁岁平安喜洋洋。\\n下联：绿竹报春福满门，年年有余乐融融。\\n横批：吉祥如意\\n\\n这副对联寓意新春佳节里，红梅傲立寒冬，象征着坚韧不拔的精神，春风温暖，预示着新的一年里充满希望和祥和；上联的“岁岁平安”和下联的“年年有余”都是祝福语，表达了对幸福生活的期盼。横批“吉祥如意”则是对美好未来的祝愿。')"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat_ty = ChatTongyi()\n",
    "chat_ty.invoke([HumanMessage(content=\"帮我写副对联\")])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 星火大模型\n",
    "\n",
    "https://python.langchain.com/docs/integrations/chat/sparkllm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='Hello! How can I assist you today?')"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat_xh = ChatSparkLLM()\n",
    "message = HumanMessage(content=\"Hello\")\n",
    "chat_xh.invoke([message])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello! How can I help you today?"
     ]
    }
   ],
   "source": [
    "# 流式调用\n",
    "chat_xh_s = ChatSparkLLM(streaming=True)\n",
    "for chunk in chat_xh_s.stream(\"Hello!\"):\n",
    "    print(chunk.content, end=\"\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 百度文心一言\n",
    "\n",
    "https://python.langchain.com/docs/integrations/chat/baidu_qianfan_endpoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [03-04 22:27:40] openapi_requestor.py:316 [t:8028]: requesting llm api endpoint: /chat/eb-instant\n",
      "[INFO] [03-04 22:27:40] oauth.py:207 [t:8028]: trying to refresh access_token for ak `og6mWr***`\n",
      "[INFO] [03-04 22:27:40] oauth.py:220 [t:8028]: sucessfully refresh access_token\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "AIMessage(content='您好！有什么我可以帮助您的吗？')"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat_wx = QianfanChatEndpoint(streaming=True)\n",
    "messages = [HumanMessage(content=\"Hello\")]\n",
    "chat_wx.invoke(messages)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [03-04 22:27:41] openapi_requestor.py:316 [t:8028]: requesting llm api endpoint: /chat/eb-instant\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "您好！有什么我可以帮助您的吗？\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    for chunk in chat_wx.stream(messages):\n",
    "        print(chunk.content, end=\"\", flush=True)\n",
    "except TypeError as e:\n",
    "    print(\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 聊天模型的使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [03-04 22:45:38] openapi_requestor.py:316 [t:8028]: requesting llm api endpoint: /chat/eb-instant\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "AIMessage(content='哇，那太酷了！你擅长什么编程语言吗？')"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "messages = [\n",
    "    SystemMessage(content=\"You are a helpful assistant that translates English to French.\"),\n",
    "    HumanMessage(content=\"I love programming.\")\n",
    "]\n",
    "chat_wx.invoke(messages)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content=\"J'adore programmer.\")"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat_ty.invoke(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "LLMResult(generations=[[ChatGeneration(text=\"J'adore programmer.\", generation_info={'finish_reason': 'stop', 'request_id': 'c07b584e-89c4-9468-a21a-ca3b05847dcd', 'token_usage': {'input_tokens': 28, 'output_tokens': 6, 'total_tokens': 34}}, message=AIMessage(content=\"J'adore programmer.\"))], [ChatGeneration(text=\"J'adore l'intelligence artificielle.\", generation_info={'finish_reason': 'stop', 'request_id': '2e5dcd4f-f3f1-9d17-96b7-5a26da1f4ba1', 'token_usage': {'input_tokens': 29, 'output_tokens': 12, 'total_tokens': 41}}, message=AIMessage(content=\"J'adore l'intelligence artificielle.\"))]], llm_output={'model_name': 'qwen-turbo'}, run=[RunInfo(run_id=UUID('5f63f25a-8cad-4056-8652-a75cd5b7ae79')), RunInfo(run_id=UUID('67cfa8fd-275c-4495-b702-37e3b3d69b6f'))])"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "batch_messages = [\n",
    "    [\n",
    "        SystemMessage(content=\"You are a helpful assistant that translates English to French.\"),\n",
    "        HumanMessage(content=\"I love programming.\")\n",
    "    ],\n",
    "    [\n",
    "        SystemMessage(content=\"You are a helpful assistant that translates English to French.\"),\n",
    "        HumanMessage(content=\"I love artificial intelligence.\")\n",
    "    ],\n",
    "]\n",
    "result = chat_ty.generate(batch_messages)\n",
    "result\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'model_name': 'qwen-turbo'}"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result.llm_output"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模版在聊天模型中的使用\n",
    "\n",
    "我们可以使用模板来构建MessagePromptTemplate。我们可以从一个或多个MessagePromptTemplate构建一个ChatPromptTemplate。我们还可以使用ChatPromptTemplate的format_prompt方法，它将返回一个PromptValue，我们可以将其转换为字符串或消息对象，具体取决于我们是否希望将格式化后的值作为输入传递给LLM或Chat模型的输入。为了方便起见，模板上公开了一个from_template方法。如果您要使用此模板，代码如下所示："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content=\"J'adore programmer.\")"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "template=\"You are a helpful assistant that translates {input_language} to {output_language}.\"\n",
    "system_message_prompt = SystemMessagePromptTemplate.from_template(template)\n",
    "human_template=\"{text}\"\n",
    "human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)\n",
    "chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])\n",
    "\n",
    "# 获取格式化后的消息的聊天完成结果\n",
    "chat_ty(chat_prompt.format_prompt(input_language=\"English\", output_language=\"French\", text=\"I love programming.\").to_messages())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### classwork-3\n",
    "\n",
    "1. 基于聊天模型实现对对联工具，人给出上联，模型给出下联\n",
    "\n",
    "2. 使用模板实现用不同语言的对对联工具"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
